
package com.autumnframework.factory;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


public  class BeanFactory {
	private static Map<String,Bean> beans=new HashMap<String,Bean>();
	
	private static Map<String,Object> objects=new HashMap<String,Object>();
	
	private static BeanFactory beanFactory;
	
	public static synchronized BeanFactory getInstance(){
		if(beanFactory==null){
			beanFactory=new BeanFactory();
			beanFactory.init();
		}
		return beanFactory;		
	}
	
	private void init(){
		InputStream inputStream=null;
		try {
			inputStream=BeanFactory.class.getClassLoader().getResourceAsStream("Bean.xml");
			DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();		
			DocumentBuilder builder=factory.newDocumentBuilder();
			Document document=builder.parse(inputStream);
			Element element=document.getDocumentElement();
			
			NodeList beanNodes=element.getElementsByTagName("bean");
			if(beanNodes==null){
				return;
			}
			int beanLength=beanNodes.getLength();
			for(int i=0;i<beanLength;i++){
				Element beanElement=(Element) beanNodes.item(i);
				Bean bean=new Bean();
				
				String id=beanElement.getAttribute("id");
				bean.setId(id);
				
				String className=beanElement.getAttribute("class");
				bean.setClassName(className);
				
				String scope=beanElement.getAttribute("scope");
				bean.setScope(scope);
				
				List<Property> proList=new ArrayList<Property>();
				NodeList propertyNodes=beanElement.getElementsByTagName("property");
				for(int j=0;j<propertyNodes.getLength();j++){
					Element propertyElement=(Element) propertyNodes.item(j);
					Property property=new Property();
					String name=propertyElement.getAttribute("name");
					property.setName(name);
					String value=propertyElement.getAttribute("value");
					property.setValue(value);
					proList.add(property);
				}
				bean.setPropertyList(proList);
				beans.put(id, bean);
				
			}
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	finally{
			if(inputStream!=null){
				try {
					inputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	public static Object getBean(String id){
		if(beans.containsKey(id)){
			Bean bean= beans.get(id);
			String className=bean.getClassName();
			String scope=bean.getScope();
			if(scope.equalsIgnoreCase("singleton")){
				if(objects.containsKey(id)){
					return objects.get(id);
				}
			}
			Class<?> clz=null;
			try {
				clz=Class.forName(className);
				Object object=clz.newInstance();
				List<Property> properties=bean.getPropertyList();
				for(Property property:properties){
					String propertyName=property.getName();
					
					//将属性名第一个字母变成大写
					String firstChar=propertyName.substring(0,1);
					String leaveChar=propertyName.substring(1);
					String methodName=firstChar.toUpperCase()+leaveChar;
					
					Method[] methods=clz.getMethods();
					Method method=null;
					for(Method methodInClass:methods){
						String methodNameInClass=methodInClass.getName();
						if(methodNameInClass.equals("set"+methodName)){
							method=methodInClass;
							break;
						}
					}
					
					Class<?>[] parmts=method.getParameterTypes();
					String propertyValue=property.getValue();
					if(parmts[0]==String.class){
						method.invoke(object, propertyValue);
					}else if(parmts[0]==int.class){
						method.invoke(object, Integer.parseInt(propertyValue));
					}else if(parmts[0]==boolean.class){
						method.invoke(object, Boolean.parseBoolean(propertyValue));
					}
				}
				if(scope.equalsIgnoreCase("singleton")){
					objects.put(id, object);
				}
				return object;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		return null;
	}
}
